package com.shkco.xbjcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.shkco.exception.GlobalExceptionCode;
import com.shkco.result.JSONResult;
import com.shkco.utils.AssertUtil;
import com.shkco.utils.CodeGenerateUtils;
import com.shkco.xbjcc.domain.Course;
import com.shkco.xbjcc.domain.CourseMarket;
import com.shkco.xbjcc.domain.KillActivity;
import com.shkco.xbjcc.domain.KillCourse;
import com.shkco.xbjcc.dto.KillCourseOrderDto;
import com.shkco.xbjcc.dto.KillPreOrderParamDto;
import com.shkco.xbjcc.feign.CourseService;
import com.shkco.xbjcc.mapper.KillCourseMapper;
import com.shkco.xbjcc.service.IKillActivityService;
import com.shkco.xbjcc.service.IKillCourseService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.shkco.xbjcc.vo.CourseInfoVo;
import com.shkco.xbjcc.vo.CourseOrderVo;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale
 * @since 2022-10-20
 */
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private IKillActivityService killActivityService;

    @Autowired
    private CourseService courseService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    public void publish(KillCourse killCourse) {
        // 根据课程id查询课程
        JSONResult jsonResult = courseService.get(killCourse.getCourseId());
        // 判断是否查询成功
        AssertUtil.isTrue(jsonResult.isSuccess(), GlobalExceptionCode.ERROR);
        Object data = jsonResult.getData();
        // 判断data中是否有数据
        AssertUtil.isNotNull(data,GlobalExceptionCode.COURSE_NO_EXISTING);
        Course course = JSON.parseObject(JSON.toJSONString(data), Course.class);
        // 判断课程是否上架状态
        boolean boo = Course.STATUS_ON_LINE == course.getStatus();
        AssertUtil.isTrue(boo,GlobalExceptionCode.ERROR);
        // 根据活动id查询活动
        KillActivity killActivity = killActivityService.selectById(killCourse.getActivityId());
        // 判断活动是否存在
        AssertUtil.isNotNull(killActivity,GlobalExceptionCode.KILL_ACTIVITY_INEXISTENCE);
        // 判断活动状态
        boolean b = killActivity.getPublishStatus() == KillActivity.TO_BE_RELEASED;
        AssertUtil.isTrue(b,GlobalExceptionCode.ERROR);
        KillCourse killCourseTemp = selectByCourseIdAndActivity(killCourse.getActivityId(), killCourse.getCourseId());
        AssertUtil.isNull(killCourseTemp,GlobalExceptionCode.KILL_COURSE_EXISTING);
        setProperties(killCourse, killActivity);
        insert(killCourse);
    }

    @Override
    public List<KillCourse> selectByActivityId(Long id) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("activity_id",id);
        return selectList(wrapper);
    }

    @Override
    public List<KillCourse> onlineAll() {
        List<KillCourse> killCourses = new ArrayList<>();
        Set<Object> keys = redisTemplate.keys("activity:*");
        keys.forEach(key ->{
            List values = redisTemplate.opsForHash().values(key);
            killCourses.addAll(values);
        });
        return killCourses;

    }

    @Override
    public KillCourse onlineOne(Long killActivityId, Long killCourseId) {
        return (KillCourse) redisTemplate.opsForHash().get("activity:" + killActivityId, killCourseId.toString());
    }

    @Override
    public String kill(KillCourseOrderDto killCourseOrderDto) {
        Long userId = 3L;
        Long killCourseId = killCourseOrderDto.getKillCourseId();
        Long killActivityId = killCourseOrderDto.getKillActivityId();
        // 从redis中拿取秒杀课程
        Object o = redisTemplate.opsForHash().get("activity:" + killActivityId, killCourseId.toString());
        // 判断拿取到的数据是否存在
        AssertUtil.isNotNull(o,GlobalExceptionCode.KILL_COURSE_INEXISTENCE);
        KillCourse killCourse = JSON.parseObject(JSON.toJSONString(o), KillCourse.class);
        // 判断当前秒杀课程是否在秒杀时间内
        AssertUtil.isTrue(killCourse.getKilling(),GlobalExceptionCode.KILL_COURSE_NOT_IN_TIME);
        // 每个秒杀商品只能秒杀一次
        Object order = redisTemplate.opsForValue().get(userId + ":" + killActivityId + ":" + killCourseId);
        AssertUtil.isNull(order,GlobalExceptionCode.PLEASE_DO_NOT_REPEAT_PURCHASE);
        RSemaphore semaphore = redissonClient.getSemaphore(killActivityId + ":" + killCourseId);
        boolean boo = semaphore.tryAcquire();
        AssertUtil.isTrue(boo,GlobalExceptionCode.STOCK_INSUFFICIENT);
        // 创建预创订单
        KillPreOrderParamDto killPreOrderParamDto = new KillPreOrderParamDto();
        String orderSn = CodeGenerateUtils.generateOrderSn(userId);
        killPreOrderParamDto.setOrderNo(orderSn);
        killPreOrderParamDto.setCourseId(killCourse.getCourseId());
        killPreOrderParamDto.setCourseName(killCourse.getCourseName());
        killPreOrderParamDto.setKillCourseId(killCourse.getId());
        killPreOrderParamDto.setCoursePic(killCourse.getCoursePic());
        killPreOrderParamDto.setKillActivityId(killCourse.getActivityId());
        killPreOrderParamDto.setTotalAmount(killCourse.getKillPrice());
        killPreOrderParamDto.setTotalCount(1);
        killPreOrderParamDto.setUserId(userId);
        // 预创订单存入redis
        redisTemplate.opsForValue().set(orderSn,killPreOrderParamDto);
        // 用户秒杀课程后存入redis，防止用户重复购买
        redisTemplate.opsForValue().set(userId + ":" + killActivityId + ":" + killCourseId,orderSn);
        return orderSn;
    }

    @Override
    public CourseInfoVo onlineOneByOrder(String orderNo) {
        Object o = redisTemplate.opsForValue().get(orderNo);
        AssertUtil.isNotNull(o,GlobalExceptionCode.ERROR);
        KillPreOrderParamDto killPreOrderParamDto = JSON.parseObject(JSON.toJSONString(o), KillPreOrderParamDto.class);

        CourseInfoVo courseInfoVo = new CourseInfoVo();
        List<CourseOrderVo> courseOrderVos = new ArrayList<>();

        CourseOrderVo courseOrderVo = new CourseOrderVo();
        Course course = new Course();
        CourseMarket courseMarket = new CourseMarket();
        course.setName(killPreOrderParamDto.getCourseName());
        course.setPic(killPreOrderParamDto.getCoursePic());
        courseMarket.setPrice(killPreOrderParamDto.getTotalAmount());
        courseOrderVo.setCourse(course);
        courseOrderVo.setCourseMarket(courseMarket);
        courseInfoVo.setTotalAmount(killPreOrderParamDto.getTotalAmount());
        courseOrderVos.add(courseOrderVo);
        courseInfoVo.setCourseInfos(courseOrderVos);
        return courseInfoVo;
    }

    private void setProperties(KillCourse killCourse, KillActivity killActivity) {
        killCourse.setKillLimit(1);
        killCourse.setStartTime(killActivity.getBeginTime());
        killCourse.setEndTime(killActivity.getEndTime());
        killCourse.setCreateTime(new Date());
        killCourse.setTimeStr(killActivity.getTimeStr());
        killCourse.setPublishStatus(killActivity.getPublishStatus());
    }

    private KillCourse selectByCourseIdAndActivity(Long activityId, Long courseId) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("activity_id",activityId);
        wrapper.eq("course_id",courseId);
        return selectOne(wrapper);
    }
}
